#ifndef _GRAPHICAL_GRAPH_H_
#define _GRAPHICAL_GRAPH_H_

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include "Graph.hpp"

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace Types {

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/*!
 * Arc data class declaration
 */
template <typename STR_T, typename COL_T, typename DAT_T>
class ArcData {

	public:

		/// Constructor
		ArcData()
		: label(""), colour_idx(-1)
		{}

		/// Constructor
		ArcData(const STR_T & label, const int colour_idx = -1)
		: label(label), colour_idx(colour_idx)
		{}

		/// Constructor
		ArcData(const STR_T & label, const int colour_idx, const DAT_T & data)
		: label(label), colour_idx(colour_idx), data(data)
		{}

		/// Creates a copy of the given instance
		ArcData(const ArcData & inst)
		: label(inst.label), colour_idx(inst.colour_idx), data(inst.data)
		{}

		/// Affectation operator
		ArcData & operator = (const ArcData & inst) {
			if (this != &inst) {
				this->label = inst.label;
				this->colour_idx = inst.colour_idx;
				this->data = inst.data;
			}
			return *this;
		}

		/// Returns the label (read-only)
		const STR_T & GetLabel() const { return this->label; }
			
		/// Returns the label value
		STR_T & Label() { return this->label; }

		/// Returns the colour index (read-only)
		const int GetColourIndex() const { return this->colour_idx; }
			
		/// Returns the colour index
		int & ColourIndex() { return this->colour_idx; }

		/// Returns the additional data (read-only)
		const DAT_T & GetAddData() const { return this->data; }
			
		// Returns the additional data
		DAT_T & AddData() { return this->data; }

	protected:

		/// Label
		STR_T label;

		/// Colour index
		int colour_idx;

		/// Data
		DAT_T data;

};

/*!
 * Node data class declaration
 */
template <typename STR_T, typename COL_T, typename DAT_T, typename LOC_T>
class NodeData : public ArcData<STR_T,COL_T,DAT_T> {

	public:

		/// Constructor
		NodeData()
		: ArcData<STR_T,COL_T,DAT_T>()
		{}

		/// Constructor
		NodeData(const STR_T & label, const int colour_idx = -1)
		: ArcData<STR_T,COL_T,DAT_T>(label, colour_idx)
		{}

		/// Constructor
		NodeData(const STR_T & label, const int colour_idx, const DAT_T & data)
		: ArcData<STR_T,COL_T,DAT_T>(label, colour_idx, data)
		{}

		/// Creates a copy of the given instance
		NodeData(const NodeData & inst)
		: ArcData<STR_T,COL_T,DAT_T>(inst), location(inst.location)
		{}

		/// Affectation operator
		NodeData & operator = (const NodeData & inst) {
			if (this != &inst) {
				//static_cast< ArcData<STR_T,COL_T,DAT_T> >(*this) = static_cast< ArcData<STR_T,COL_T,DAT_T> >(inst);
				this->label = inst.label;
				this->colour_idx = inst.colour_idx;
				this->data = inst.data;
				this->location = inst.location;
			}
			return *this;
		}

		/// Returns the location (read-only)
		const LOC_T & GetLocation() const { return this->location; }
			
		/// Returns the location
		LOC_T & Location() { return this->location; }

	protected:

		/// Location
		LOC_T location;

};

/**
 *  Graphical Graph class
 *	A graphical graph is made of nodes and arcs of type GraphData.
 *	NodeData and ArcData holds the relevant information to nodes and arcs.
 *	The string, colour, node data and location and arc data types need to be provided.
 */
template <typename STR_T, typename COL_T, typename N_DAT_T, typename LOC_T, typename A_DAT_T>
class GraphicalGraph : public Types::Graph< NodeData<STR_T,COL_T,N_DAT_T,LOC_T>, ArcData<STR_T,COL_T,A_DAT_T> > {

	public:

		/// Returns the graph palette
		const std::vector<COL_T> & GetGPalette() const { return this->g_palette; }

		/// Sets the graph palette
		void SetGPalette(const std::vector<COL_T> & value) { this->g_palette = value; }

		/// Get graph palette at the given index
		const COL_T & GetGPaletteAt(const unsigned int idx) { return this->g_palette[idx]; }

		/// Set graph palette at the given index
		void SetGPaletteAt(const unsigned int idx, const COL_T & value) { this->g_palette[idx] = value; }

		/// Add a colour at the end of the palette
		void AddColour(const COL_T & value) { this->g_palette.push_back(value); }

		/// Remove colour at the given index
		void RemoveColourAt(const unsigned int idx) { this->g_palette.erase(this->g_palette.begin()+idx); }

	protected:

		/// Graph colour palette
		std::vector<COL_T> g_palette;

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
